home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 March
/
EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso
/
earcd
/
comm2
/
mfstlntd.lha
/
telnetd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-02
|
70KB
|
1,701 lines
/*
* $Filename: telnetd.c $
* $Revision: 2.0 $
* $Date: 1995/04/13 19:53:48 $
*
* Copyright (C) 1993,94 by Steve Holland <sdh4@cornell.edu>
* Copyright (C) 1995 by Peter Simons <simons@peti.rhein.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: telnetd.c 2.0 1995/04/13 19:53:48 simons Exp $
*
* *********************************************************
* * WARNING WARNING WARNING WARNING WARNING !!! *
* *********************************************************
*
* Telnetd source code has been modified by Andrea Rafreider
* (andsk@amiga.dei.unipd.it) in order to make it MultiUser compatible.
*
* This modify of the original source code from Steve Holland and
* Peter Simons was made on date 1995/05/04.
*
* Original version of telnetd2.0 with source can be found in this
* same archive.
*
* Watch the file Multiuser.txt to see what is MultiUser, and what can
* be done with it.
*
* With *this* modified telnetd, passwd checking is done via
* multiuser.library instead of usergroup.library from AmiTCP.
*
* The main advantage is that giving a shell to a remote user is
* no longer *totally* insecure because of multiuser protection
* mechanisms.
*
* Obviously for better security the system manager should protect
* all the "hot" commands with root permissions only.
*
* It's no longer possible to log in without password if the passwd field
* in the multiuser passwd file is "*".
* Some annoying syslog messages have also been removed.
*
* The password checking is done via multiuser.library so that multiuser
* passwd file can be protected from indiscreet eyes with the following
* protection bits: root ----rwed group ---- other ----
*
* I really don't see why AmiTCP group have complicated things not
* using ACrypt() criptographic function from Commodore. To set up
* a multiuser environement with AmiTCP one should have two passwd
* files !! One for AmiTCP, and another one for MultiUser!!
* This is ridiculous.
*
* In our amiga system at University we don't use AmiTCP passwd file
* at all ! Clients don't need it and as daemons we use JoranFTPd and
* now this modified telnetd.
*
* I'm considering the idea of creating a fake usergroup.library from
* the free usergroup.library source code that makes passwd checks via
* ACrypt() function from Commodore, so we could end up with this silly
* problems.
*
* That's all folks!!
* Andrea Rafreider.
*
* Please see also the GNU General Public Licence included in this archive.
* to agree with terms and conditions of the distribution of this package.
*/
/************************************* includes ***********/
#include <exec/types.h>
#include <exec/memory.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/utility.h>
#include <proto/usergroup.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <exec/errors.h>
#include <devices/serial.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <inetd.h>
#include <syslog.h>
#include <amitcp/socketbasetags.h>
/* Next 3 includes are added by Mr. Andsk */
#include <utility/tagitem.h>
#include <libraries/multiuser.h>
#include <proto/multiuser.h>
#include <fakesr.h>
#include "telnetd_rev.h"
/************************************* structures *********/
struct InstData {
struct Library *DOSB;
struct Library *SocketB;
struct Library *UtilityB;
struct Library *UserGroupB;
int Socket;
signed short RecvBuf[1024];
int RecvBufPos;
int RecvBufFlags;
};
struct PasswdInfo {
char Login[50];
char Passwd[50];
char RealName[150];
char WorkDir[256];
char Command[512];
};
/************************************* defines ************/
#define DOSBase Inst->DOSB
#define UtilityBase Inst->UtilityB
#define SocketBase Inst->SocketB
#define UserGroupBase Inst->UserGroupB
#define Socket Inst->Socket
/* telnet symbols */
#define IAC 255
#define WILL 251
#define WONT 252
#define DO 253
#define DONT 254
#define ECHO 1
#define LINEMODE 34
#define SE 240
#define SB 250
#define MODE 1
#define EDIT 1
#define RBF_SUBNEGOTIATE (1<<0) /* Defines for RecvBufFlags */
/************************************* global variables ***/
static const char __DOSVer[] = VERSTAG " written by Peter Simons <simons@peti.rhein.de>";
#ifndef USE_INETD
struct Library *SysBase;
#endif
char *Signature="FAKEMSG--EXPUNGE";
/************************************* prototypes *********/
void SockPuts(struct InstData *Inst,int Sock,char *Buf);
void SockGets(struct InstData *Inst,int Sock,char *Buf,int BufSize);
unsigned long GetInt(char *String,char **NewPtr);
struct PasswdInfo *LookupPasswd(struct InstData *Inst,char *Login);
int __asm SubSubProc(register __a0 char *ArgString,register __d0 long Length);
struct DosPacket *PktFromMsg(struct Message *Msg);
void MakeLongStr(char *StrBuf,unsigned long Num);
void SockWrite(struct InstData *Inst,int Sock,char *Buf,int Len,int RawFlag);
int RecvChar(struct InstData *Inst,int Sock,unsigned char *Loc,int RawMode);
struct Process *MyCreateNewProcTags(struct InstData *,ULONG,...);
void *MyAllocDosObjectTags(struct InstData *,ULONG,ULONG,...);
void PktFPuts(struct InstData *Inst,BPTR File,char *String);
void SockRawWrite(struct InstData *Inst,int Sock,char *Buf,int Len);
void MySystemTags(struct Library *DSBse,char *Cmd,ULONG Tag0,...);
void mystrcat(char *Dest,char *Cat);
void MyFPrintf(struct InstData *Inst,BPTR File,char *Fmt,...);
ULONG FakeBeginIO(void *IORequest);
ULONG FakeAbortIO(void *IORequest);
ULONG FakeOpen(void *IORequest);
ULONG FakeClose(void *IORequest);
void mymovmem(char *From,char *To,int Len);
#define NewList(list) {(list)->lh_Head=(struct Node *)&(list)->lh_Tail;(list)->lh_Tail=NULL;(list)->lh_TailPred=(struct Node *)&(list)->lh_Head;}
#ifdef DEBUG
BPTR DebugFile;
#endif
#ifdef USE_INETD
int main(void)
#else
int __asm main(register __a0 char *ArgStr,register __d0 long Length)
/* ArgString will look like: "[SocketID] [SigNum] [ParentTaskID]" */
#endif
{
int Cnt;
char A_Buf[20]; /* temporary buffer for ACrypt() */
unsigned long SockID,SigID,TaskID;
char Buf[1000],LoginBuf[50], MyPrgName[64];
BPTR BannerFile=NULL;
struct muBase *muBase = NULL; /* added by andsk */
struct TagItem tags[3]; /* added by andsk */
struct muUserInfo *muInfo = NULL; /* added by andsk */
struct InstData *Inst=NULL;
struct PasswdInfo *Info=NULL;
struct FileHandle *FH;
struct Message *Msg,*GotMsg;
unsigned char NoEcho[7];
unsigned char Echo[14];
char *ArgString;
int OpenCount=0;
int AmntRead;
int HangupFlag=FALSE;
ULONG SigMask;
long yes=TRUE;
fd_set RdSet;
fd_set WrSet;
struct List ReadWaitList;
struct DosPacket *Pkt;
int Err;
unsigned char Chr,NumBuf[30];
int RawMode=FALSE;
int NextChar=-1;
struct MsgPort *TimePort;
struct timerequest *TimeReq;
struct DaemonMessage *InetdStartup;
struct Process *Self;
#ifndef USE_INETD
SysBase=*((struct Library **)0x00000004);
ArgString=ArgStr;
#endif
Echo[0]=NoEcho[0]=IAC;
Echo[1]=WONT;
Echo[2]=ECHO;
Echo[3]=IAC;
Echo[4]=DO;
Echo[5]=LINEMODE;
Echo[6]=IAC;
Echo[7]=SB;
Echo[8]=LINEMODE;
Echo[9]=MODE;
Echo[10]=EDIT;
Echo[11]=IAC;
Echo[12]=SE;
NoEcho[1]=WILL;
NoEcho[2]=ECHO;
NoEcho[3]=IAC;
NoEcho[4]=DONT;
NoEcho[5]=LINEMODE;
Echo[13]=NoEcho[6]='\0';
#ifndef USE_INETD
for (Cnt=0;Cnt < Length;Cnt++) {
if (ArgStr[Cnt]!=' ' && (ArgStr[Cnt] < '0' || ArgStr[Cnt] > '9'))
return ERROR_FILE_NOT_OBJECT;
}
#endif
Inst=AllocMem(sizeof(struct InstData),MEMF_CLEAR);
if (!Inst) return 0;
muBase=OpenLibrary("multiuser.library",39); /* added by andsk */
DOSBase=OpenLibrary("dos.library",36);
UtilityBase=OpenLibrary("utility.library",36);
SocketBase=OpenLibrary("bsdsocket.library",2);
UserGroupBase=OldOpenLibrary(USERGROUPNAME);
TimePort=CreateMsgPort();
NewList(&ReadWaitList);
if (!DOSBase || !UtilityBase || !SocketBase || !UserGroupBase || !TimePort || !muBase) return 0; /* added check for multiuser.library */
SocketBaseTags(SBTM_SETVAL(SBTC_LOGTAGPTR), "telnetd",
SBTM_SETVAL(SBTC_LOGSTAT), 0,
SBTM_SETVAL(SBTC_LOGFACILITY), LOG_AUTH,
TAG_END);
#ifdef DEBUG
DebugFile=Open("con:0/0/500/100/telnetd DEBUG/WAIT/CLOSE",MODE_OLDFILE);
FPuts(DebugFile,"telnetd starting\n");
# ifndef USE_INETD
FPuts(DebugFile,"ArgString=");
FPuts(DebugFile,ArgString);
FPuts(DebugFile,"\n");
# endif
#endif
#ifdef USE_INETD
Self=(struct Process *) FindTask(NULL);
InetdStartup=(struct DaemonMessage *)Self->pr_ExitData;
if (!InetdStartup) goto quit;
Socket=ObtainSocket(InetdStartup->dm_Id,InetdStartup->dm_Family,InetdStartup->dm_Type,0);
if (Socket < 0) goto quit;
#else
/* Get arguments */
SockID=GetInt(ArgString,&ArgString);
ArgString++; /* Skip over space */
SigID=GetInt(ArgString,&ArgString);
ArgString++; /* Skip over space */
TaskID=GetInt(ArgString,&ArgString);
/* After this call, the parameter string is no longer valid */
Signal((struct Task *)TaskID,1<<SigID);
#ifdef DEBUG
FPuts(DebugFile,"Signaled parent\n");
#endif
/* We're on our own now */
Socket=ObtainSocket(SockID,AF_INET,SOCK_STREAM,0);
if (Socket < 0) goto quit;
#endif
#ifdef DEBUG
FPuts(DebugFile,"Got Socket\n");
#endif
/* First, display banner, ask for password, etc */
if (BannerFile=Open("AmiTCP:db/telnetd_banner",MODE_OLDFILE)) {
int len = 1;
while(TRUE) {
len = Read(BannerFile, Buf, sizeof(Buf));
if (!len || len == -1)
break;
SockWrite(Inst,Socket,Buf,len,FALSE);
}
Close(BannerFile);
}
#ifdef DEBUG
FPuts(DebugFile,"Wrote banner to socket\n");
#endif
/* Get login name */
SockPuts(Inst,Socket,"Login: ");
SockPuts(Inst,Socket,Echo);
SockGets(Inst,Socket,LoginBuf,sizeof(LoginBuf));
while (strlen(LoginBuf) && (LoginBuf[strlen(LoginBuf)-1]=='\n' || LoginBuf[strlen(LoginBuf)-1]=='\r'))
LoginBuf[strlen(LoginBuf)-1]='\0';
#ifdef DEBUG
FPuts(DebugFile,"Got Login: ");
FPuts(DebugFile,LoginBuf);
FPuts(DebugFile,"\n");
#endif
/* Info = LookupPasswd(Inst, LoginBuf); not needed anymore */
/* We get now info for connecting user via multiuser.library */
if (muInfo = muAllocUserInfo()) {
strcpy(muInfo->UserID,LoginBuf);
if (!muGetUserInfo(muInfo,muKeyType_UserID)) {
muFreeUserInfo(muInfo);
muInfo = NULL;
}
else if (Info=AllocMem(sizeof(struct PasswdInfo),MEMF_PUBLIC)) {
strcpy(Info->Login,muInfo->UserID);
strcpy(Info->Passwd,"faked_passwd!"); /* not returned by muGetUserInfo, not needed anyway! */
strcpy(Info->RealName,muInfo->UserName);
strcpy(Info->WorkDir,muInfo->HomeDir);
strcpy(Info->Command,muInfo->Shell);
}
else
syslog(LOG_CRIT, "Couldn't allocate my info structure!");
}
else
syslog(LOG_CRIT, "Couldn't allocate memory muInfo structure!");
/*
* We don't get asked for password if user doesn't exist
* or the shell is equal "nologin", we are just pulled out.
*
* WARNING !!
*
* Code is changed a little bit ..
* No more you can get logged in if your passwd is "*" for multiuser
* compatibility.
*/
if (Info && strcmp("nologin", Info->Command)) {
strcpy(Buf, "Password: ");
strcpy(Buf+strlen(Buf), NoEcho);
SockPuts(Inst, Socket, Buf);
SockGets(Inst, Socket, Buf,sizeof(Buf));
while (strlen(Buf) && (Buf[strlen(Buf)-1]=='\n' || Buf[strlen(Buf)-1]=='\r'))
Buf[strlen(Buf)-1]='\0';
SockPuts(Inst,Socket,Echo);
#ifdef DEBUG
FPuts(DebugFile,"Got Password: ");
FPuts(DebugFile,Buf);
FPuts(DebugFile,"\n");
#endif
SockPuts(Inst,Socket,"\n");
/* We must be sure that current user is nobody */
tags[0].ti_Tag = muT_Quiet;
tags[0].ti_Data = TRUE;
tags[1].ti_Tag = TAG_DONE;
(void) muLogoutA(tags);
/* MultiUser login */
tags[0].ti_Tag = muT_UserID;
tags[0].ti_Data = Info->Login;
tags[1].ti_Tag = muT_Password;
tags[1].ti_Data = Buf;
tags[2].ti_Tag = TAG_DONE;
if (!muLoginA(tags)) {
SockPuts(Inst,Socket,"Login failed!\n");
CloseSocket(Socket);
goto quit;
}
}
else {
SockPuts(Inst,Socket,"\nUser does not exist or has not telnet access to this machine.\nClosing connection\n");
CloseSocket(Socket);
goto quit;
}
sprintf(MyPrgName, "telnetd <%s>", Info->Login);
SetProgramName(MyPrgName);
if (Info->Command[0]=='*') {
/* Use stdin/stdout */
/* Make myself a filehandle */
#ifdef DEBUG
FPuts(DebugFile,"Logged in OK\nMaking Filehandle\n");
#endif
FH=MyAllocDosObjectTags(Inst,DOS_FILEHANDLE,ADO_FH_Mode,MODE_OLDFILE,TAG_END);
if (!FH) goto quit;
FH->fh_Pos=FH->fh_End=-1;
FH->fh_Type=&((struct Process *)FindTask(NULL))->pr_MsgPort;
FH->fh_Args=(LONG)Info;
FH->fh_Port=FH->fh_Type; /* Is this right? */
FH=(struct FileHandle *)MKBADDR(FH);
OpenCount++;
/* Run the subprocess */
MakeLongStr(Buf,(ULONG)FH);
strcpy(Buf+strlen(Buf)," ");
strcpy(Buf+strlen(Buf),Info->Command+1 /* ignore the leading '*' */);
#ifdef DEBUG
FPuts(DebugFile,"Starting subprocess\nCmdLine=");
FPuts(DebugFile,Buf);
FPuts(DebugFile,"\n");
/*Close(DebugFile);*/
Flush(DebugFile);
/*DebugFile=NULL;*/
#endif
/* NO more DOS calls allowed after this one */
/* We also can't use Buf after we make this call */
if (*(Info->Command+1)) {
MyCreateNewProcTags(Inst,NP_Entry,SubSubProc,
NP_Arguments,Buf,
TAG_END);
}
FD_ZERO(&RdSet);
IoctlSocket(Socket,FIONBIO,(caddr_t)&yes);
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Starting handler support\n");
#endif
for (;;) {
if (ReadWaitList.lh_Head->ln_Succ && !HangupFlag) {
if (NextChar != -1) {
Pkt=PktFromMsg((struct Message *)ReadWaitList.lh_Head);
*(((unsigned char *)Pkt->dp_Arg2)+Pkt->dp_Res1)=NextChar;
Chr=NextChar;
NextChar=-1;
Err=1;
Pkt->dp_Res1++;
if (Pkt->dp_Res1==Pkt->dp_Arg3 || Chr=='\r' || Chr=='\n') {
Remove(ReadWaitList.lh_Head);
PutMsg(Pkt->dp_Port,Pkt->dp_Link); /* Send it back */
}
}
}
if (ReadWaitList.lh_Head->ln_Succ && !HangupFlag) {
FD_SET(Socket,&RdSet);
} else {
FD_CLR(Socket,&RdSet);
}
SigMask=(1<<((struct Process *)FindTask(NULL))->pr_MsgPort.mp_SigBit)|(1<<TimePort->mp_SigBit);
WaitSelect(Socket+1,&RdSet,NULL,NULL,NULL,&SigMask);
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Wait ended \n");
#endif
if (FD_ISSET(Socket,&RdSet)) {
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got read available from socket\n");
#endif
if (ReadWaitList.lh_Head->ln_Succ) {
/* Someone is waiting to read */
Pkt=PktFromMsg((struct Message *)ReadWaitList.lh_Head);
if (Pkt && Pkt->dp_Type==ACTION_READ) {
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Performing delayed read\n");
#endif
while (Pkt->dp_Res1 < Pkt->dp_Arg3) {
if (NextChar != -1) {
*(((unsigned char *)Pkt->dp_Arg2)+Pkt->dp_Res1)=NextChar;
Chr=NextChar;
NextChar=-1;
Err=1;
} else {
Err=RecvChar(Inst,Socket,((char *)Pkt->dp_Arg2)+Pkt->dp_Res1,FALSE/*RawMode*/);
Chr=*(((char *)Pkt->dp_Arg2)+Pkt->dp_Res1);
}
if (Err==1) Pkt->dp_Res1++;
else if (Err==0) {
/* Hangup */
HangupFlag=TRUE;
break;
} else break;
#ifdef DEBUG
if (Chr==255) {
PktFPuts(Inst,DebugFile,"Received 255\n");
}
#endif
if (Chr=='\r' || Chr=='\n') {
break;
}
}
if (Err==1) {
if (Pkt->dp_Res1==Pkt->dp_Arg3 ||
Chr=='\r' || Chr=='\n') {
Remove(ReadWaitList.lh_Head);
/* syslog(LOG_DEBUG, "Sending out \"%s\"",
* &Pkt->dp_Link+sizeof(struct Message));
*/
PutMsg(Pkt->dp_Port,Pkt->dp_Link); /* Send it back */
}
}
} else if (Pkt && Pkt->dp_Type==ACTION_WAIT_CHAR) {
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Processing WAIT_CHAR");
#endif
if (NextChar==-1) {
Err=RecvChar(Inst,Socket,&Chr,FALSE);
if (Err==1) {
Pkt->dp_Res1=DOSTRUE;
Remove(ReadWaitList.lh_Head);
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"char ready\n");
#endif
AbortIO((struct IORequest *)Pkt->dp_Res2);
WaitIO((struct IORequest *)Pkt->dp_Res2);
CloseDevice((struct IORequest *)Pkt->dp_Res2);
DeleteIORequest((struct IORequest *)Pkt->dp_Res2);
Pkt->dp_Res2=0;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
NextChar=Chr;
} else {
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"no char available\n");
#endif
NextChar=-1;
}
if (Err==0) HangupFlag=TRUE;
} else {
Pkt->dp_Res1=DOSTRUE;
Remove(ReadWaitList.lh_Head);
AbortIO((struct IORequest *)Pkt->dp_Res2);
WaitIO((struct IORequest *)Pkt->dp_Res2);
CloseDevice((struct IORequest *)Pkt->dp_Res2);
DeleteIORequest((struct IORequest *)Pkt->dp_Res2);
Pkt->dp_Res2=0;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"char ready\n");
#endif
}
}
else { /* Invalid message */
Remove(ReadWaitList.lh_Head);
}
} else {
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Unexpected: got read ready, no request\n");
#endif
}
}
while (TimeReq=(struct timerequest *)GetMsg(TimePort)) {
Msg=(struct Message *)TimeReq->tr_node.io_Message.mn_Node.ln_Name;
Pkt=PktFromMsg(Msg);
CloseDevice(TimeReq);
DeleteIORequest(TimeReq);
Pkt->dp_Res1=DOSFALSE;
Pkt->dp_Res2=0;
Remove(Msg); /* Remove it from the read wait list */
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
}
while (Msg=GetMsg(&((struct Process *)FindTask(NULL))->pr_MsgPort)) {
Pkt=PktFromMsg(Msg);
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got packet\n");
#endif
switch(Pkt->dp_Type) {
case ACTION_FINDINPUT:
case ACTION_FINDOUTPUT:
case ACTION_FINDUPDATE:
FH=(struct FileHandle *)BADDR((BPTR)Pkt->dp_Arg1);
FH->fh_Pos=FH->fh_End=-1;
FH->fh_Type=&((struct Process *)FindTask(NULL))->pr_MsgPort;
FH->fh_Args=(LONG)Info;
FH->fh_Port=FH->fh_Type; /* Is this right? */
OpenCount++;
Pkt->dp_Res1=DOSTRUE;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
break;
case ACTION_READ:
Pkt->dp_Res1=0;
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got action_read\n");
#endif
AddTail(&ReadWaitList,Msg);
break;
case ACTION_WRITE:
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got action_write\n");
#endif
SockWrite(Inst,Socket,(char *)Pkt->dp_Arg2,Pkt->dp_Arg3,FALSE/*RawMode*/);
Pkt->dp_Res1=Pkt->dp_Arg3;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
break;
case ACTION_WAIT_CHAR:
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got action_waitchar");
#endif
Pkt->dp_Res1=DOSFALSE;
TimeReq=CreateIORequest(TimePort,sizeof(struct timerequest));
if (!TimeReq || OpenDevice("timer.device",UNIT_MICROHZ,TimeReq,0)) {
if (TimeReq)
DeleteIORequest(TimeReq);
Pkt->dp_Res2=ERROR_NO_FREE_STORE;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
}
TimeReq->tr_node.io_Command=TR_ADDREQUEST;
TimeReq->tr_time.tv_micro=Pkt->dp_Arg1;
TimeReq->tr_time.tv_secs=0;
TimeReq->tr_node.io_Message.mn_Node.ln_Name=Msg;
SendIO(TimeReq);
Pkt->dp_Res2=(ULONG)TimeReq;
AddTail(&ReadWaitList,Msg);
break;
/*
case ACTION_DISKINFO:
break;
*/
case ACTION_SCREEN_MODE:
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got action_screen_mode\n");
#endif
if (Pkt->dp_Arg1) {
/* Raw mode */
SockPuts(Inst,Socket,NoEcho);
RawMode=TRUE;
} else {
SockPuts(Inst,Socket,Echo);
RawMode=FALSE;
}
Pkt->dp_Res1=DOSFALSE;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
break;
case ACTION_END:
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got action_end\n");
#endif
Pkt->dp_Res1=0;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
OpenCount--;
if (!OpenCount) {
for (GotMsg=(struct Message *)ReadWaitList.lh_Head;GotMsg->mn_Node.ln_Succ;GotMsg=(struct Message *)GotMsg->mn_Node.ln_Succ) {
Pkt=PktFromMsg(GotMsg);
if (Pkt->dp_Type==ACTION_WAIT_CHAR) {
AbortIO((struct IORequest *)Pkt->dp_Res2);
WaitIO((struct IORequest *)Pkt->dp_Res2);
CloseDevice((struct IORequest *)Pkt->dp_Res2);
DeleteIORequest((struct IORequest *)Pkt->dp_Res2);
Pkt->dp_Res2=0;
}
}
goto quit;
}
break;
case ACTION_SEEK:
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got action_seek\n");
#endif
Pkt->dp_Res1=-1;
Pkt->dp_Res2=ERROR_OBJECT_WRONG_TYPE;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
break;
default:
#ifdef DEBUG
PktFPuts(Inst,DebugFile,"Got action_not_known. Number");
MakeLongStr(NumBuf,Pkt->dp_Type);
PktFPuts(Inst,DebugFile,NumBuf);
PktFPuts(Inst,DebugFile,"\n");
#endif
Pkt->dp_Res1=0;
Pkt->dp_Res2=ERROR_ACTION_NOT_KNOWN;
PutMsg(Pkt->dp_Port,Pkt->dp_Link);
}
}
}
} else {
/* Use fake serial */
struct IOStdReq *IOReq=NULL;
struct MsgPort *IOPort=NULL;
struct FSRUnit *SerUnit=NULL;
/* SerUnit->fsru_UserData[0]=CmdPort
SerUnit->fsru_UserData[1]=ReadQueue
SerUnit->fsru_UserData[2]=WriteQueue
SerUnit->fsru_UserData[3]=Open count
SerUnit->fsru_UserData[4]=RBufLen */
struct MsgPort *CmdPort=NULL;
struct List *ReadQueue=NULL;
struct List *WriteQueue=NULL;
char *CmdPtr;
struct IOExtSer *GotReq=NULL,*OtrReq=NULL;
char *RBuf=NULL;
int RBufPos=0;
int SerUnitAdded=FALSE;
int Amnt;
int RecvRet;
int CD=TRUE; /* Carrier Detect */
long UnitNum=FSR_UNITNONE;
/* We use IOExtSer.Status bit 0 as a flag to say whether this request has
been aborted */
#ifdef DEBUG
FPuts(DebugFile,"Creating ports...\n");
#endif
IOPort=CreateMsgPort();
CmdPort=CreateMsgPort();
IOReq=CreateIORequest(IOPort,sizeof(struct IOStdReq));
if (!IOPort || !IOReq || !CmdPort) {
#ifdef DEBUG
FPuts(DebugFile,"Unable to create message port/IORequest\nExiting\n");
#endif
goto quitfakeser;
}
#ifdef DEBUG
FPuts(DebugFile,"Opening fakesr.device...\n");
#endif
if (OpenDevice("fakesr.device",FSR_CTLUNIT,IOReq,0)) {
IOReq->io_Device=NULL;
#ifdef DEBUG
FPuts(DebugFile,"Unable to open fakesr.device\nExiting\n");
#endif
goto quitfakeser;
}
#ifdef DEBUG
FPuts(DebugFile,"opened successfully\n");
#endif
SerUnit=AllocMem(sizeof(struct FSRUnit),MEMF_CLEAR|MEMF_PUBLIC);
ReadQueue=AllocMem(sizeof(struct List),MEMF_PUBLIC);
if (ReadQueue) NewList(ReadQueue);
WriteQueue=AllocMem(sizeof(struct List),MEMF_PUBLIC);
if (WriteQueue) NewList(WriteQueue);
if (!SerUnit || !ReadQueue || !WriteQueue) {
#ifdef DEBUG
FPuts(DebugFile,"Unable to allocate memory\nExiting\n");
#endif
goto quitfakeser;
}
CmdPtr=Info->Command;
if (Info->Command[0]<='9' && Info->Command[0] >= '0') {
UnitNum=GetInt(Info->Command,&CmdPtr);
}
SerUnit->fsru_Num=UnitNum;
SerUnit->fsru_BeginIO=FakeBeginIO;
SerUnit->fsru_AbortIO=FakeAbortIO;
SerUnit->fsru_Open=FakeOpen;
SerUnit->fsru_Close=FakeClose;
SerUnit->fsru_UserData[0]=CmdPort;
SerUnit->fsru_UserData[1]=ReadQueue;
SerUnit->fsru_UserData[2]=WriteQueue;
SerUnit->fsru_UserData[3]=0;
SerUnit->fsru_UserData[4]=(void *)1024;
IOReq->io_Data=(APTR)SerUnit;
IOReq->io_Length=sizeof(*SerUnit);
IOReq->io_Command=FSRCMD_ADDUNIT;
IOReq->io_Error=0;
#ifdef DEBUG
FPuts(DebugFile,"Adding FakeSr unit...");
#endif
DoIO(IOReq);
if (IOReq->io_Error) {
#ifdef DEBUG
FPuts(DebugFile,"Error adding fakesr.device unit\nExiting\n");
#endif
goto quitfakeser;
}
SerUnitAdded=TRUE;
#ifdef DEBUG
FPuts(DebugFile,"Done\n");
#endif
RBuf=AllocMem((ULONG)SerUnit->fsru_UserData[4],MEMF_PUBLIC);
RBufPos=0;
if (!RBuf) {
#ifdef DEBUG
FPuts(DebugFile,"Unable to allocate memory\nExiting\n");
#endif
goto quitfakeser;
}
IoctlSocket(Socket,FIONBIO,(caddr_t)&yes);
{
BPTR NilInput,NilOutput;
#ifdef DEBUG
FPuts(DebugFile,"Opening filehandles\n");
#endif
if (*CmdPtr) {
NilInput=Open("NIL:",MODE_OLDFILE);
NilOutput=Open("NIL:",MODE_OLDFILE);
/* sprintf(Buf,"%s -DEVICE fakesr.device -UNIT %ld",CmdPtr,SerUnit->fsru_Num); */
strcpy(Buf,CmdPtr);
mystrcat(Buf," -DEVICE fakesr.device -UNIT ");
MakeLongStr(LoginBuf,SerUnit->fsru_Num);
#ifdef DEBUG
FPuts(DebugFile,"Got FakeSr unit: ");
FPuts(DebugFile,LoginBuf);
FPuts(DebugFile,"\n");
#endif
SockPuts(Inst,Socket,NoEcho);
mystrcat(Buf,LoginBuf);
#ifdef DEBUG
FPuts(DebugFile,"Running command:");
FPuts(DebugFile,Buf);
FPuts(DebugFile,"\n");
#endif
MySystemTags(DOSBase,Buf,SYS_Input,NilInput,SYS_Output,NilOutput,SYS_Asynch,TRUE,TAG_END);
}
}
for (;;) {
FD_ZERO(&RdSet);
FD_ZERO(&WrSet);
if (CD) {
if (RBufPos < (((long)SerUnit->fsru_UserData[4])-1)) FD_SET(Socket,&RdSet);
if (WriteQueue->lh_Head->ln_Succ) FD_SET(Socket,&WrSet);
}
SigMask=(1<<CmdPort->mp_SigBit)|SIGBREAKF_CTRL_C;
WaitSelect(Socket+1,&RdSet,&WrSet,NULL,NULL,&SigMask);
#ifdef DEBUG
FPuts(DebugFile,"Wait ended...");
#endif
if (FD_ISSET(Socket,&RdSet)) {
while ((RBufPos < (long)SerUnit->fsru_UserData[4]) && ((RecvRet=RecvChar(Inst,Socket,RBuf+RBufPos,TRUE))==1)) RBufPos++;
Forbid();
if ((GotReq=(struct IOExtSer *)ReadQueue->lh_Head)->IOSer.io_Message.mn_Node.ln_Succ) {
Remove(GotReq);
Permit();
Amnt=min(RBufPos,GotReq->IOSer.io_Length);
memcpy(((char *)GotReq->IOSer.io_Data)+GotReq->IOSer.io_Actual,RBuf,Amnt);
GotReq->IOSer.io_Actual+=Amnt;
if (Amnt < RBufPos) mymovmem(RBuf+Amnt,RBuf,RBufPos-Amnt);
RBufPos-=Amnt;
if (GotReq->IOSer.io_Actual < GotReq->IOSer.io_Length) {
if (GotReq->io_Status & (1<<0)) {
/* We got an AbortIO() */
GotReq->IOSer.io_Error=IOERR_ABORTED;
ReplyMsg(GotReq);
} else {
Forbid();
AddTail(ReadQueue,GotReq);
Permit();
}
}
else ReplyMsg(GotReq);
}
else Permit();
if (RecvRet==0) {
/* Connection closed */
CD=FALSE;
}
}
if (FD_ISSET(Socket,&WrSet)) {
Forbid();
if ((GotReq=(struct IOExtSer *)WriteQueue->lh_Head)->IOSer.io_Message.mn_Node.ln_Succ) {
Remove(GotReq);
Permit();
#ifdef DEBUG
FPuts(DebugFile,"Writing to socket\n");
MyFPrintf(Inst,DebugFile,"io_Actual=%ld,io_Length=%ld\n",(long)GotReq->IOSer.io_Actual,(long)GotReq->IOSer.io_Length);
#endif
SockWrite(Inst,Socket,((char *)GotReq->IOSer.io_Data)+GotReq->IOSer.io_Actual,GotReq->IOSer.io_Length-GotReq->IOSer.io_Actual,TRUE);
#ifdef DEBUG
FPuts(DebugFile,"Write completed\n");
#endif
GotReq->IOSer.io_Actual=GotReq->IOSer.io_Length;
if (GotReq->IOSer.io_Actual < GotReq->IOSer.io_Length) {
Forbid();
if (GotReq->io_Status & (1<<0)) {
Permit();
/* We got an AbortIO() */
GotReq->IOSer.io_Error=IOERR_ABORTED;
ReplyMsg(GotReq);
} else {
AddTail(WriteQueue,GotReq);
Permit();
}
} else {
#ifdef DEBUG
FPuts(DebugFile,"Replying write message\n");
#endif
ReplyMsg(GotReq);
}
} else {
Permit();
}
}
while (GotReq=(struct IOExtSer *)GetMsg(CmdPort)) {
if (GotReq->IOSer.io_Message.mn_Node.ln_Name==Signature) {
/* We just use the pointer as a signature */
/* We just got an expunge request */
#ifdef DEBUG
FPuts(DebugFile,"Got expunge request\n");
#endif
FreeMem(GotReq,sizeof(struct Message)); /* We free the expunge request instead of reply */
Forbid();
if (SerUnit->fsru_UserData[3]==0) {
/* Open count==0 */
if (SerUnitAdded) {
IOReq->io_Command=FSRCMD_REMUNIT;
IOReq->io_Data=(APTR)SerUnit;
IOReq->io_Length=sizeof(*SerUnit);
DoIO(IOReq);
SerUnitAdded=FALSE;
}
if (SerUnit->fsru_UserData[3]==0) {
/* If opencnt is still 0 */
Permit();
goto quitfakeser; /* exit */
}
}
Permit();
}
else {
#ifdef DEBUG
FPuts(DebugFile,"Got cmd...");
#endif
switch(GotReq->IOSer.io_Command) {
case CMD_CLEAR:
#ifdef DEBUG
FPuts(DebugFile,"Got CMD_CLEAR\n");
#endif
RBufPos=0;
GotReq->IOSer.io_Error=0;
ReplyMsg(GotReq);
break;
case CMD_FLUSH:
case CMD_RESET:
#ifdef DEBUG
FPuts(DebugFile,"Got CMD_FLUSH/RESET\n");
#endif
Forbid();
while (OtrReq=(struct IOExtSer *)RemHead(ReadQueue)) {
OtrReq->IOSer.io_Error=IOERR_ABORTED;
ReplyMsg(OtrReq);
}
while (OtrReq=(struct IOExtSer *)RemHead(WriteQueue)) {
OtrReq->IOSer.io_Error=IOERR_ABORTED;
ReplyMsg(OtrReq);
}
Permit();
GotReq->IOSer.io_Error=0;
ReplyMsg(GotReq);
break;
case CMD_READ:
#ifdef DEBUG
FPuts(DebugFile,"Got CMD_READ\n");
#endif
GotReq->IOSer.io_Actual=0;
GotReq->IOSer.io_Error=0;
Amnt=min(RBufPos,GotReq->IOSer.io_Length);
memcpy(((char *)GotReq->IOSer.io_Data)+GotReq->IOSer.io_Actual,RBuf,Amnt);
GotReq->IOSer.io_Actual+=Amnt;
if (Amnt < RBufPos) mymovmem(RBuf+Amnt,RBuf,Amnt);
RBufPos-=Amnt;
if (GotReq->IOSer.io_Actual < GotReq->IOSer.io_Length) {
Forbid();
AddTail(ReadQueue,GotReq);
Permit();
}
else ReplyMsg(GotReq);
break;
case CMD_START:
#ifdef DEBUG
FPuts(DebugFile,"Got CMD_START\n");
#endif
GotReq->IOSer.io_Error=0;
ReplyMsg(GotReq);
break;
case CMD_STOP:
#ifdef DEBUG
FPuts(DebugFile,"Got CMD_STOP\n");
#endif
GotReq->IOSer.io_Error=0;
ReplyMsg(GotReq);
break;
case CMD_WRITE:
#ifdef DEBUG
FPuts(DebugFile,"Got CMD_WRITE\n");
#endif
GotReq->IOSer.io_Actual=0;
GotReq->IOSer.io_Error=0;
Forbid();
AddTail(WriteQueue,GotReq);
Permit();
break;
case SDCMD_BREAK:
#ifdef DEBUG
FPuts(DebugFile,"Got SDCMD_BREAK\n");
#endif
GotReq->IOSer.io_Error=0;
ReplyMsg(GotReq);
break;
case SDCMD_QUERY:
#ifdef DEBUG
FPuts(DebugFile,"Got SDCMD_QUERY\n");
#endif
GotReq->IOSer.io_Actual=RBufPos;
GotReq->io_Status=0x0000 | ((CD) ? 0:(1<<5));
GotReq->IOSer.io_Error=0;
ReplyMsg(GotReq);
break;
case SDCMD_SETPARAMS:
#ifdef DEBUG
FPuts(DebugFile,"Got SDCMD_SETPARAMS\n");
#endif
GotReq->IOSer.io_Error=0;
ReplyMsg(GotReq);
break;
default:
#ifdef DEBUG
FPuts(DebugFile,"Got CMD_UNKNOWN\n");
#endif
GotReq->IOSer.io_Error=IOERR_NOCMD;
ReplyMsg(GotReq);
}
}
}
}
quitfakeser:
if (ReadQueue) {
Forbid();
while (GotReq=(struct IOExtSer *)RemHead(ReadQueue)) {
GotReq->IOSer.io_Error=IOERR_ABORTED;
GotReq->IOSer.io_Actual=0;
ReplyMsg(GotReq);
}
Permit();
FreeMem(ReadQueue,sizeof(struct List));
}
if (WriteQueue) {
Forbid();
while (GotReq=(struct IOExtSer *)RemHead(WriteQueue)) {
GotReq->IOSer.io_Error=IOERR_ABORTED;
GotReq->IOSer.io_Actual=0;
ReplyMsg(GotReq);
}
Permit();
FreeMem(WriteQueue,sizeof(struct List));
}
if (RBuf && SerUnit) {
FreeMem(RBuf,(long)SerUnit->fsru_UserData[4]);
}
if (SerUnit) {
if (SerUnitAdded && IOReq) {
IOReq->io_Data=(APTR)SerUnit;
IOReq->io_Length=sizeof(*SerUnit);
IOReq->io_Command=FSRCMD_REMUNIT;
DoIO(IOReq);
}
FreeMem(SerUnit,sizeof(struct FSRUnit));
}
if (IOReq) {
if (IOReq->io_Device) CloseDevice(IOReq);
DeleteIORequest(IOReq);
}
if (IOPort) DeleteMsgPort(IOPort);
if (CmdPort) DeleteMsgPort(CmdPort);
goto quit;
}
quit:
#ifdef DEBUG
if (DebugFile) Close(DebugFile);
#endif
SocketBaseTags(SBTM_SETVAL(SBTC_LOGTAGPTR), NULL, TAG_END);
if (TimePort) DeleteMsgPort(TimePort);
if (Info) FreeMem(Info,sizeof(struct PasswdInfo));
if (muInfo) muFreeUserInfo(muInfo); /* added by andsk */
if (Inst) {
if (muBase) CloseLibrary((struct Library *)muBase); /* added by andsk */
if (UserGroupBase) CloseLibrary(UserGroupBase);
if (SocketBase) CloseLibrary(SocketBase);
if (UtilityBase) CloseLibrary(UtilityBase);
if (DOSBase) CloseLibrary(DOSBase);
}
return 0;
}
void MyFPrintf(struct InstData *Inst,BPTR File,char *Fmt,...)
{
VFPrintf(File,Fmt,(&Fmt)+1);
}
void mystrcat(char *Dest,char *Cat)
{
memcpy(Dest+strlen(Dest),Cat,strlen(Cat)+1);
}
void mymovmem(char *From,char *To,int Len)
{
int Cnt;
if (From > To) {
for (Cnt=0;Cnt < Len;Cnt++) {
To[Cnt]=From[Cnt];
}
} else if (From < To) {
for (Cnt=Len-1;Cnt >= 0;Cnt--) {
To[Cnt]=From[Cnt];
}
}
}
struct Node *FindNode(struct List *List,struct Node *Node)
/* returns Node if Node is a member of list, NULL otherwise */
{
struct Node *ChkNode;
for (ChkNode=List->lh_Head;ChkNode->ln_Succ;ChkNode=ChkNode->ln_Succ) {
if (ChkNode==Node) return Node;
}
return NULL;
}
ULONG FakeBeginIO(void *IORequest)
{
((struct IORequest *)IORequest)->io_Flags &= ~IOF_QUICK; /* Quick IO not supported */
((struct IOExtSer *)IORequest)->io_Status &= ~(1<<0); /* clear abort bit */
((struct Node *)IORequest)->ln_Name=NULL; /* clear possible signature */
PutMsg((struct MsgPort *)((struct FSRUnit *)((struct IORequest *)IORequest)->io_Unit)->fsru_UserData[0],IORequest);
return 0;
}
ULONG FakeAbortIO(void *IORequest)
{
struct IOExtSer *Ser;
Ser=IORequest;
Forbid();
Ser->io_Status |= (1<<0); /* Flag the request as aborted */
if (FindNode(((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[1],Ser) ||
FindNode(((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[2],Ser)) {
/* This IORequest is waiting to be processed */
Remove(Ser);
Ser->IOSer.io_Error=IOERR_ABORTED;
Ser->IOSer.io_Actual=0;
ReplyMsg(Ser);
}
else {
/* This IORequest is currently being processed -- send a break */
Signal(((struct MsgPort *)((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[0])->mp_SigTask,SIGBREAKF_CTRL_C);
}
Permit();
return 0;
}
ULONG FakeOpen(void *IORequest)
{
struct IOExtSer *Ser;
Ser=IORequest;
Forbid();
((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[3]=(void *) ((long)(((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[3])+1); /* Increment opencnt */
Permit();
Ser->IOSer.io_Error=0;
Ser->io_CtlChar=SER_DEFAULT_CTLCHAR;
Ser->io_RBufLen=(long)((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[4];
Ser->io_ExtFlags=0;
Ser->io_Baud=19200;
Ser->io_BrkTime=250000;
Ser->io_TermArray.TermArray0=0;
Ser->io_TermArray.TermArray1=0;
Ser->io_ReadLen=8;
Ser->io_WriteLen=8;
Ser->io_StopBits=1;
Ser->io_Status=0;
return 0;
}
ULONG FakeClose(void *IORequest)
{
struct IOExtSer *Ser;
struct Message *Msg;
Ser=IORequest;
Forbid();
((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[3]=(void *) ((long)(((struct FSRUnit *)Ser->IOSer.io_Unit)->fsru_UserData[3])-1); /* Decrement opencnt */
Msg=AllocMem(sizeof(struct Message),MEMF_PUBLIC|MEMF_CLEAR);
Msg->mn_Node.ln_Name=Signature;
PutMsg((struct MsgPort *)((struct FSRUnit *)((struct IORequest *)IORequest)->io_Unit)->fsru_UserData[0],Msg);
Permit();
return 0;
}
struct DosPacket *PktFromMsg(struct Message *Msg)
{
return (struct DosPacket *)Msg->mn_Node.ln_Name;
}
void PktFPuts(struct InstData *Inst,BPTR File,char *String)
{
struct MsgPort *ReplyPort;
struct DosPacket *Pkt;
ReplyPort=CreateMsgPort();
Pkt=AllocDosObject(DOS_STDPKT,NULL);
if (!Pkt || !ReplyPort) return;
Pkt->dp_Type=ACTION_WRITE;
Pkt->dp_Arg1=((struct FileHandle *)BADDR(File))->fh_Arg1;
Pkt->dp_Arg2=(LONG) String;
Pkt->dp_Arg3=strlen(String);
Pkt->dp_Port=ReplyPort;
PutMsg(((struct FileHandle *)BADDR(File))->fh_Type,Pkt->dp_Link);
WaitPort(ReplyPort);
GetMsg(ReplyPort);
DeleteMsgPort(ReplyPort);
FreeDosObject(DOS_STDPKT,Pkt);
}
unsigned long GetInt(char *String,char **NewPtr)
{
unsigned long Num=0;
char *Junk;
long Cnt;
long BaseNum;
if (!NewPtr) NewPtr=&Junk;
for (*NewPtr=String;;(*NewPtr)++) {
if (**NewPtr < '0' || **NewPtr > '9') return Num;
/* AAARGH!! multiplication causes a lib call to be generated.
We can't use the library. Therefore we have to add */
/* Num=Num*10; */
for (BaseNum=Num,Cnt=0;Cnt < 9;Cnt++,Num+=BaseNum);
Num+=**NewPtr-'0';
}
}
void SockPuts(struct InstData *Inst,int Sock,char *Buf)
{
int BufPos=0;
int BytesWritten;
do {
BytesWritten=send(Sock,Buf+BufPos,strlen(Buf+BufPos),0);
if (BytesWritten > 0) BufPos+=BytesWritten;
} while (Buf[BufPos]);
}
void SockRawWrite(struct InstData *Inst,int Sock,char *Buf,int Len)
{
int BufPos=0;
int BytesWritten;
if (!Len) return;
do {
BytesWritten=send(Sock,Buf+BufPos,Len-BufPos,0);
if (BytesWritten > 0) BufPos+=BytesWritten;
} while (Len-BufPos);
}
void SockWrite(struct InstData *Inst,int Sock,char *Buf,int Len,int RawFlag)
{
int Cnt;
int BufPos=0;
unsigned char iac2[2];
char eol[2];
char csi[2];
iac2[0]=iac2[1]=IAC;
eol[0]='\r';
eol[1]='\n';
csi[0]='\x1b';
csi[1]='[';
while (Len > BufPos) {
for (Cnt=BufPos;Cnt < Len;Cnt++) {
if (!RawFlag)
if (Buf[Cnt]=='\r' || Buf[Cnt]=='\n') break;
if (Buf[Cnt]=='\x9b') break;
if (Buf[Cnt]==IAC) {
break;
}
}
SockRawWrite(Inst,Sock,Buf+BufPos,Cnt-BufPos);
BufPos=Cnt;
if (BufPos < Len && Buf[BufPos]==IAC) { /* If we got single IAC, send double IAC */
BufPos++;
SockRawWrite(Inst,Sock,iac2,2);
}
if (!RawFlag) {
if (BufPos < Len && Buf[BufPos]=='\r') {
BufPos++;
}
if (BufPos < Len && Buf[BufPos]=='\n') {
BufPos++;
SockRawWrite(Inst,Sock,eol,2);
}
if (BufPos < Len && Buf[BufPos]=='\x9b') {
BufPos++;
SockRawWrite(Inst,Sock,csi,2);
}
}
}
}
void ParseBuf3(struct InstData *Inst)
/* Parse 3 character remote request */
{
}
void ParseBuf2(struct InstData *Inst)
/* Parse 2 character remote-request */
{
}
void ParseBufSubNegotiate(struct InstData *Inst)
{
}
int RecvChar(struct InstData *Inst,int Sock,unsigned char *Loc,int RawMode)
{
int GotLen;
unsigned char Got,TrueGot;
/*RawMode=TRUE;*/
static unsigned char PrevChar;
do {
GotLen=recv(Sock,&Got,1,0); /* Wait for a character */
if (GotLen==-1) {
if (Errno()==EINTR) continue;
else return -1;
} else if (GotLen==0) return 0;
TrueGot=Got;
if (!Inst->RecvBufPos && GotLen==1 && Got==0) GotLen=-1; /* Read again */
if (GotLen==1 && !RawMode && !Inst->RecvBufPos) {
/* These next few lines ignore incoming newlines and convert
incoming CRs into newlines */
if (Got=='\n' && PrevChar=='\r') GotLen=-1; /* Read again. */
if (Got=='\r') Got='\n';
}
} while (GotLen != 1);
/* *Loc=Got;
return 1; */
if (Inst->RecvBufPos) {
Inst->RecvBuf[Inst->RecvBufPos]=Got;
Inst->RecvBufPos++;
switch (Inst->RecvBufPos) {
case 2:
switch(Inst->RecvBuf[1]) {
case IAC:
/* Just a single IAC */
*Loc=IAC;
return 1;
break;
case SB:
Inst->RecvBufFlags|=RBF_SUBNEGOTIATE;
return RecvChar(Inst,Sock,Loc,RawMode);
break;
case SE:
Inst->RecvBufPos=0;
Inst->RecvBufFlags &= ~RBF_SUBNEGOTIATE;
return RecvChar(Inst,Sock,Loc,RawMode);
case WILL:
case WONT:
case DO:
case DONT:
return RecvChar(Inst,Sock,Loc,RawMode);
break;
default:
ParseBuf2(Inst);
Inst->RecvBufPos=0;
return RecvChar(Inst,Sock,Loc,RawMode);
}
break;
default:
if (Inst->RecvBufFlags & RBF_SUBNEGOTIATE) {
if (Inst->RecvBufPos >= 2 && Inst->RecvBuf[Inst->RecvBufPos-2]==IAC && Inst->RecvBuf[Inst->RecvBufPos-1]!=IAC) {
/* End of subnegotiation */
Inst->RecvBuf[0]=IAC;
if ((Inst->RecvBuf[1]=Inst->RecvBuf[Inst->RecvBufPos-1])==SE) {
Inst->RecvBufFlags &= ~RBF_SUBNEGOTIATE;
Inst->RecvBufPos=0;
return RecvChar(Inst,Sock,Loc,RawMode);
}
Inst->RecvBufPos=2;
ParseBufSubNegotiate(Inst);
}
if (Inst->RecvBufPos >= 2 && Inst->RecvBuf[Inst->RecvBufPos-2]==IAC && Inst->RecvBuf[Inst->RecvBufPos-1]==IAC) {
/* We just got a double IAC in subnegotiation */
Inst->RecvBuf[Inst->RecvBufPos-2]=-1; /* We store IAC as a (int)-1 */
Inst->RecvBufPos--;
}
return RecvChar(Inst,Sock,Loc,RawMode);
} else {
if (Inst->RecvBuf[2]==IAC) {
/* Restart sequence */
Inst->RecvBuf[0]=IAC;
Inst->RecvBufPos=1;
return RecvChar(Inst,Sock,Loc,RawMode);
} else {
ParseBuf3(Inst);
Inst->RecvBufPos=0;
return RecvChar(Inst,Sock,Loc,RawMode);
}
}
break;
}
}
else {
if (Got==IAC) {
Inst->RecvBuf[0]=Got;
Inst->RecvBufPos=1;
return RecvChar(Inst,Sock,Loc,RawMode);
} else {
*Loc=Got;
PrevChar=TrueGot;
return 1;
}
}
return 1;
}
void SockGets(struct InstData *Inst,int Sock,char *Buf,int BufSize)
/* This function gets the next string until a CR
on the specified socket, and places it in buf. It
discards leading crs/lfs */
{
int BufPos=0;
int BytesRead;
int FirstBytes=TRUE;
Buf[0]='\0';
do {
BytesRead=RecvChar(Inst,Sock,Buf+BufPos,FALSE);
if (BytesRead < 0) {
if (Errno()!=EINTR) {
Buf[BufPos]='\0';
return;
}
}
else if (BytesRead==0) {
Buf[BufPos]='\0';
return;
}
else {
if ((Buf[BufPos]=='\r' || Buf[BufPos]=='\n') && FirstBytes) {
Buf[BufPos]='\0';
} else {
FirstBytes=FALSE;
BufPos+=BytesRead;
}
}
} while (Buf[BufPos-1] != '\r' && Buf[BufPos-1] != '\n' && BufPos < (BufSize-1));
Buf[BufPos]='\0';
}
char *PullPasswdString(char **StringPtr)
{
int Cnt;
char *RetVal;
char *CurPos;
if (!StringPtr || !*StringPtr) return NULL;
RetVal=*StringPtr;
for (CurPos=RetVal;*CurPos != ',' && *CurPos != '\r' && *CurPos != '\n' && *CurPos;CurPos++);
switch (*CurPos) {
case ',':
case '\r':
case '\n':
*CurPos='\0';
CurPos++;
*StringPtr=CurPos;
return RetVal;
case '\0':
*StringPtr=CurPos;
return RetVal;
}
}
int mystrcmp(char *S1,char *S2)
{
int Cnt;
for (Cnt=0;S1[Cnt] && S2[Cnt];Cnt++) {
if (S1[Cnt] != S2[Cnt]) return !0;
}
if (S1[Cnt] != S2[Cnt]) return !0;
return 0;
}
struct PasswdInfo *LookupPasswd(struct InstData *Inst,char *Login)
{
BPTR File;
char *LineBuf;
char *BufPtr;
char *PasswdPtr;
char *LoginPtr;
char *RealNamePtr;
char *HomeDirPtr;
char *CmdPtr;
struct PasswdInfo *Info = NULL;
struct passwd *result;
if (result = getpwnam(Login)) {
if (Info=AllocMem(sizeof(struct PasswdInfo),MEMF_PUBLIC)) {
strcpy(Info->Login,result->pw_name);
strcpy(Info->Passwd,result->pw_passwd);
strcpy(Info->RealName,result->pw_gecos);
strcpy(Info->Command,result->pw_shell);
}
else
syslog(LOG_CRIT, "Couldn't allocate my info structure!");
}
else
;
/* syslog(LOG_INFO, "user %s is unknown here", Login); */
return Info;
}
void __asm PutMLSChar(register __d0 char Chr,register __a3 char **BufPtr)
{
**BufPtr=Chr;
(*BufPtr)++;
}
void MakeLongStr(char *StrBuf,unsigned long Num)
{
RawDoFmt("%lu",&Num,PutMLSChar,&StrBuf);
}
struct Process *MyCreateNewProcTags(struct InstData *Inst,ULONG Tag1,...)
{
return CreateNewProc((struct TagItem *)&Tag1);
}
void *MyAllocDosObjectTags(struct InstData *Inst,ULONG Type,ULONG Tag1,...)
{
return AllocDosObject(Type,(struct TagItem *)&Tag1);
}
void MySystemTags(struct Library *DSBse,char *Cmd,ULONG Tag0,...)
{
#undef DOSBase
#define DOSBase DSBse
SystemTagList(Cmd,(struct TagItem *)&Tag0);
#undef DOSBase
}
#define DOSBase DSBse
int __asm __saveds SubSubProc(register __a0 char *ArgString,register __d0 long Length)
{
char StringBuf[1000];
char *StringPtr;
BPTR FH;
struct Library *DSBse;
DSBse=OpenLibrary("dos.library",36);
if (!DSBse) return 0;
FH=(BPTR)GetInt(ArgString,&StringPtr);
/* if (IsInteractive(FH)) {
Write(FH,"Interactive\n",12);
}*/
strcpy(StringBuf,StringPtr);
MySystemTags(DSBse,(StringBuf[0]) ? StringBuf : "execute S:remote-startup",
SYS_Input,FH,
SYS_Output,FH,
NP_ConsoleTask,((struct FileHandle *)BADDR(FH))->fh_Type,
NP_Cli,TRUE,
TAG_END);
Forbid();
Close(FH);
return 0;
}
#undef DOSBase